{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Denoising Autoencoder\n",
    "\n",
    "Sticking with the MNIST dataset, let's add noise to our data and see if we can define and train an autoencoder to _de_-noise the images.\n",
    "\n",
    "<img src='notebook_ims/autoencoder_denoise.png' width=70%/>\n",
    "\n",
    "Let's get started by importing our libraries and getting the dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# The MNIST datasets are hosted on yann.lecun.com that has moved under CloudFlare protection\n",
    "# Run this script to enable the datasets download\n",
    "# Reference: https://github.com/pytorch/vision/issues/1938\n",
    "from six.moves import urllib\n",
    "opener = urllib.request.build_opener()\n",
    "opener.addheaders = [('User-agent', 'Mozilla/5.0')]\n",
    "urllib.request.install_opener(opener)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import numpy as np\n",
    "from torchvision import datasets\n",
    "import torchvision.transforms as transforms\n",
    "\n",
    "# convert data to torch.FloatTensor\n",
    "transform = transforms.ToTensor()\n",
    "\n",
    "# load the training and test datasets\n",
    "train_data = datasets.MNIST(root='~/.pytorch/MNIST_data/', train=True,\n",
    "                                   download=True, transform=transform)\n",
    "test_data = datasets.MNIST(root='~/.pytorch/MNIST_data/', train=False,\n",
    "                                  download=True, transform=transform)\n",
    "\n",
    "# Create training and test dataloaders\n",
    "num_workers = 0\n",
    "# how many samples per batch to load\n",
    "batch_size = 20\n",
    "\n",
    "# prepare data loaders\n",
    "train_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size, num_workers=num_workers)\n",
    "test_loader = torch.utils.data.DataLoader(test_data, batch_size=batch_size, num_workers=num_workers)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Visualize the Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x11df12ba8>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\nKAa3AAAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 360x360 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "    \n",
    "# obtain one batch of training images\n",
    "dataiter = iter(train_loader)\n",
    "images, labels = dataiter.next()\n",
    "images = images.numpy()\n",
    "\n",
    "# get one image from the batch\n",
    "img = np.squeeze(images[0])\n",
    "\n",
    "fig = plt.figure(figsize = (5,5)) \n",
    "ax = fig.add_subplot(111)\n",
    "ax.imshow(img, cmap='gray')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "# Denoising\n",
    "\n",
    "As I've mentioned before, autoencoders like the ones you've built so far aren't too useful in practive. However, they can be used to denoise images quite successfully just by training the network on noisy images. We can create the noisy images ourselves by adding Gaussian noise to the training images, then clipping the values to be between 0 and 1.\n",
    "\n",
    ">**We'll use noisy images as input and the original, clean images as targets.** \n",
    "\n",
    "Below is an example of some of the noisy images I generated and the associated, denoised images.\n",
    "\n",
    "<img src='notebook_ims/denoising.png' />\n",
    "\n",
    "\n",
    "Since this is a harder problem for the network, we'll want to use _deeper_ convolutional layers here; layers with more feature maps. You might also consider adding additional layers. I suggest starting with a depth of 32 for the convolutional layers in the encoder, and the same depths going backward through the decoder.\n",
    "\n",
    "#### TODO: Build the network for the denoising autoencoder. Add deeper and/or additional layers compared to the model above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ConvDenoiser(\n",
      "  (conv1): Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "  (conv2): Conv2d(32, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "  (conv3): Conv2d(16, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "  (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n",
      "  (t_conv1): ConvTranspose2d(8, 8, kernel_size=(3, 3), stride=(2, 2))\n",
      "  (t_conv2): ConvTranspose2d(8, 16, kernel_size=(2, 2), stride=(2, 2))\n",
      "  (t_conv3): ConvTranspose2d(16, 32, kernel_size=(2, 2), stride=(2, 2))\n",
      "  (conv_out): Conv2d(32, 1, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      ")\n"
     ]
    }
   ],
   "source": [
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "# define the NN architecture\n",
    "class ConvDenoiser(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(ConvDenoiser, self).__init__()\n",
    "        ## encoder layers ##\n",
    "        # conv layer (depth from 1 --> 32), 3x3 kernels\n",
    "        self.conv1 = nn.Conv2d(1, 32, 3, padding=1)  \n",
    "        # conv layer (depth from 32 --> 16), 3x3 kernels\n",
    "        self.conv2 = nn.Conv2d(32, 16, 3, padding=1)\n",
    "        # conv layer (depth from 16 --> 8), 3x3 kernels\n",
    "        self.conv3 = nn.Conv2d(16, 8, 3, padding=1)\n",
    "        # pooling layer to reduce x-y dims by two; kernel and stride of 2\n",
    "        self.pool = nn.MaxPool2d(2, 2)\n",
    "        \n",
    "        ## decoder layers ##\n",
    "        # transpose layer, a kernel of 2 and a stride of 2 will increase the spatial dims by 2\n",
    "        self.t_conv1 = nn.ConvTranspose2d(8, 8, 3, stride=2)  # kernel_size=3 to get to a 7x7 image output\n",
    "        # two more transpose layers with a kernel of 2\n",
    "        self.t_conv2 = nn.ConvTranspose2d(8, 16, 2, stride=2)\n",
    "        self.t_conv3 = nn.ConvTranspose2d(16, 32, 2, stride=2)\n",
    "        # one, final, normal conv layer to decrease the depth\n",
    "        self.conv_out = nn.Conv2d(32, 1, 3, padding=1)\n",
    "\n",
    "\n",
    "    def forward(self, x):\n",
    "        ## encode ##\n",
    "        # add hidden layers with relu activation function\n",
    "        # and maxpooling after\n",
    "        x = F.relu(self.conv1(x))\n",
    "        x = self.pool(x)\n",
    "        # add second hidden layer\n",
    "        x = F.relu(self.conv2(x))\n",
    "        x = self.pool(x)\n",
    "        # add third hidden layer\n",
    "        x = F.relu(self.conv3(x))\n",
    "        x = self.pool(x)  # compressed representation\n",
    "        \n",
    "        ## decode ##\n",
    "        # add transpose conv layers, with relu activation function\n",
    "        x = F.relu(self.t_conv1(x))\n",
    "        x = F.relu(self.t_conv2(x))\n",
    "        x = F.relu(self.t_conv3(x))\n",
    "        # transpose again, output should have a sigmoid applied\n",
    "        x = F.sigmoid(self.conv_out(x))\n",
    "                \n",
    "        return x\n",
    "\n",
    "# initialize the NN\n",
    "model = ConvDenoiser()\n",
    "print(model)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## Training\n",
    "\n",
    "We are only concerned with the training images, which we can get from the `train_loader`.\n",
    "\n",
    ">In this case, we are actually **adding some noise** to these images and we'll feed these `noisy_imgs` to our model. The model will produce reconstructed images based on the noisy input. But, we want it to produce _normal_ un-noisy images, and so, when we calculate the loss, we will still compare the reconstructed outputs to the original images!\n",
    "\n",
    "Because we're comparing pixel values in input and output images, it will be best to use a loss that is meant for a regression task. Regression is all about comparing quantities rather than probabilistic values. So, in this case, I'll use `MSELoss`. And compare output images and input images as follows:\n",
    "```\n",
    "loss = criterion(outputs, images)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# specify loss function\n",
    "criterion = nn.MSELoss()\n",
    "\n",
    "# specify loss function\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 1 \tTraining Loss: 0.977538\n",
      "Epoch: 2 \tTraining Loss: 0.690527\n",
      "Epoch: 3 \tTraining Loss: 0.640184\n",
      "Epoch: 4 \tTraining Loss: 0.613912\n",
      "Epoch: 5 \tTraining Loss: 0.595001\n",
      "Epoch: 6 \tTraining Loss: 0.582570\n",
      "Epoch: 7 \tTraining Loss: 0.572466\n",
      "Epoch: 8 \tTraining Loss: 0.564127\n",
      "Epoch: 9 \tTraining Loss: 0.556832\n",
      "Epoch: 10 \tTraining Loss: 0.549967\n",
      "Epoch: 11 \tTraining Loss: 0.544791\n",
      "Epoch: 12 \tTraining Loss: 0.541313\n",
      "Epoch: 13 \tTraining Loss: 0.537340\n",
      "Epoch: 14 \tTraining Loss: 0.534824\n",
      "Epoch: 15 \tTraining Loss: 0.531550\n",
      "Epoch: 16 \tTraining Loss: 0.529537\n",
      "Epoch: 17 \tTraining Loss: 0.527350\n",
      "Epoch: 18 \tTraining Loss: 0.525628\n",
      "Epoch: 19 \tTraining Loss: 0.523231\n",
      "Epoch: 20 \tTraining Loss: 0.522199\n"
     ]
    }
   ],
   "source": [
    "# number of epochs to train the model\n",
    "n_epochs = 20\n",
    "\n",
    "# for adding noise to images\n",
    "noise_factor=0.5\n",
    "\n",
    "for epoch in range(1, n_epochs+1):\n",
    "    # monitor training loss\n",
    "    train_loss = 0.0\n",
    "    \n",
    "    ###################\n",
    "    # train the model #\n",
    "    ###################\n",
    "    for data in train_loader:\n",
    "        # _ stands in for labels, here\n",
    "        # no need to flatten images\n",
    "        images, _ = data\n",
    "        \n",
    "        ## add random noise to the input images\n",
    "        noisy_imgs = images + noise_factor * torch.randn(*images.shape)\n",
    "        # Clip the images to be between 0 and 1\n",
    "        noisy_imgs = np.clip(noisy_imgs, 0., 1.)\n",
    "                \n",
    "        # clear the gradients of all optimized variables\n",
    "        optimizer.zero_grad()\n",
    "        ## forward pass: compute predicted outputs by passing *noisy* images to the model\n",
    "        outputs = model(noisy_imgs)\n",
    "        # calculate the loss\n",
    "        # the \"target\" is still the original, not-noisy images\n",
    "        loss = criterion(outputs, images)\n",
    "        # backward pass: compute gradient of the loss with respect to model parameters\n",
    "        loss.backward()\n",
    "        # perform a single optimization step (parameter update)\n",
    "        optimizer.step()\n",
    "        # update running training loss\n",
    "        train_loss += loss.item()*images.size(0)\n",
    "            \n",
    "    # print avg training statistics \n",
    "    train_loss = train_loss/len(train_loader)\n",
    "    print('Epoch: {} \\tTraining Loss: {:.6f}'.format(\n",
    "        epoch, \n",
    "        train_loss\n",
    "        ))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Checking out the results\n",
    "\n",
    "Here I'm adding noise to the test images and passing them through the autoencoder. It does a suprising great job of removing the noise, even though it's sometimes difficult to tell what the original number is."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n7S1Rd/p/VeUalH7meuaWsc8ceeSRqR37/bZt21JbIzTN/LaPcyud98doI3Uwcynu1AUAAAAAAACA\nCuGiLgAAAAAAAABUCBd1AQAAAAAAAKBC6g74LJpRkcuI0jynQYMGudrw4cNr/t3o0aNTe/Xq1a6m\nWSwx92vt2rX7fZ7ZvpmEmnkxefJkV9u9e3dqL1682NU2b96c2jErQ/NYy2aqVj13rqiimUbxeWvW\nrEnt7373u642atSo1Nb+ZWb2ile8IrXjNj322GNTO+bwzJw50z3Wbaz9xMxs06ZNqa3Zu2blc5qK\n5kCVycBuF0W/G/2/4nbKZUDp68cMmzLvHV8n5ixdcskl7vGrX/3q1L722mtdTftM2c9WVpUz57q7\nu0vlzJX9n3O5cjGj6Stf+Upqxzww7Ssve9nLXE2PX/HxwoULXe2RRx5J7bIZWLlsxlxWWJX7jVnx\nHDT9v+Lf5LJK9bHmK8fXzH2uRo3h8XPrvEQzLc3Mxo0bl9r//ve/XU2zxeJr6mct+v/1Zrl+o3I5\nhmW/q/j963wljlNnn322e3zuueemtubMmZktWbIktePcptnzjaqPN2U+by5jNI4per40bdo0V9Pn\nxm26fv361K7nGFJP/qbWYlbmpz/96dRet26dq11zzTWprXnOZj7bsLdmo+bmN/VkMRd9bvw7zfuP\n/Wbq1KmprVmoZv44cf/997ta3I5Kf1vCzJ9bNSpPuBk5ve2ozPwmbn+dJ+TG91ymbvw7HYve/OY3\nu9oHPvCB1I6Z/XGerLm58TcLtP89++yzrvbPf/4ztWNurn62J5980mqJY6+ORVXuXz2Zo5v73rQW\n5y96fVH7hNm++bdDhw5NbT0fNzO77LLLUjtmhOt519VXX+1qOieKimblHszciTt1AQAAAAAAAKBC\nuKgLAAAAAAAAABVSLgugTvEW/ne84x2pHW8zPv/881N7wIABrqa39MdlpyeddFJqx1uuN27cWPP9\nduzY4R6fcsopqR2Xlzz//PP7fU0zs3/84x+pfdddd7nafffdl9rxNnJdJqBL4pAXv0ddlhNvcdc4\njLiE4tFHH03t2E91mfOYMWNcLd7Gr8uE5syZ42q6XRu1ZLDKSzqaKbdMo56/K/rcoksMzczOOOMM\n91ijQB5//HFX0z7cqO1bJrLDrHqxHWXU8x0X3eYf/ehHXe1jH/tYasflPHpsifEtzzzzTM3nvuY1\nr3E1XZI4b948V9NxqJ7lqUW/G8ahfN/Q+czhhx/ualu2bEntGBGl2y0edw5mebTS/vjhD3/Y1S68\n8MLUvu6661ztxhtvrPlZckswe5NGL6Mvu/+Vfb8YCfaGN7zBPdY4jqefftrVbr311tRu1FJN5jbF\n6fmDLjs1M/vGN76R2qeeeqqraezcX//6V1fT401c4q5LuA8Ut5CbJ+nYEOfWunRf5+dmfi4fz5eK\nzvU6UT37kc7/4jm49rErrrjC1fS8PtJ4vDgPfu6559zjrVu3pvbnP/95V9OIl3r6W2+N42i2+N3o\n3CTG7ej4H79/PYeItREjRqR2jOPU6zzLli1zNV0eH8UIzDvvvDO1f/zjH7uajnfx3EfHqTif0bEw\nzsvoU/tXzxit33f8Po844ojUjlEvM2bMSG2N3jTbN7JDx7NY03mRRnGa+UiyOCf6wQ9+kNrxXK4V\nxyju1AUAAAAAAACACuGiLgAAAAAAAABUCBd1AQAAAAAAAKBCWpKpGzOTNOtv2LBhrvbYY4+l9jHH\nHONq69atS+2YW6qZlDFbatKkSTXfL362Pn36pHbMytDMmJjbe+6556Z23759XW3u3LmpHfODYqYv\nDl7MdtPvOJcXGrPltL8df/zxrtavXz/3WDOWlyxZkv08tdSTA1U057TTsn3i9m12VmGkrxlzU887\n7zz3WLO3Fy9e7GrN6DNFX4dsujztY/F4opnsn/jEJ1xN+0PMWlq9enVqx0z2e++91z0ePHhwasc8\nqVe+8pWpHTPPdDzL5aFFnZCpXFbcV3KZk0ozwcz8bwm86lWvcjXNxozbQt8vHr8izUeMufPTp09P\n7Te96U2udtRRR6X25MmTXU2Pg7FPNypjtTfq6TFW+1E8Zpxwwgk1/+7aa691jzX/MiIbt/HiuYXu\n07oPm5m99rWvTe04X83lSOZ+20O3acyYjK+To/PpL33pS66mr/urX/3K1fQYVnZ8oS/m5fKOdb4T\nc+G1T+l2io81B9rM7OKLL3aP169fn9pxW+VyW1UzMnU7sd/EOYWODXEuot9P7lwrjmGaVxp/K+kP\nf/hDam/atMnVfv3rX7vH2jdiPqpeA4jHrGZv107sN0XpWBN/S0LHCb2+Zmb27ne/O7Xj9T7tJ9u3\nb3c1/T0SM5+9vHLlSlfTa5EXXXSRq+n8Pdb097X02p/ZvvPuZuBOXQAAAAAAAACoEC7qAgAAAAAA\n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\n",
      "text/plain": [
       "<Figure size 1800x288 with 20 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# obtain one batch of test images\n",
    "dataiter = iter(test_loader)\n",
    "images, labels = dataiter.next()\n",
    "\n",
    "# add noise to the test images\n",
    "noisy_imgs = images + noise_factor * torch.randn(*images.shape)\n",
    "noisy_imgs = np.clip(noisy_imgs, 0., 1.)\n",
    "\n",
    "# get sample outputs\n",
    "output = model(noisy_imgs)\n",
    "# prep images for display\n",
    "noisy_imgs = noisy_imgs.numpy()\n",
    "\n",
    "# output is resized into a batch of iages\n",
    "output = output.view(batch_size, 1, 28, 28)\n",
    "# use detach when it's an output that requires_grad\n",
    "output = output.detach().numpy()\n",
    "\n",
    "# plot the first ten input images and then reconstructed images\n",
    "fig, axes = plt.subplots(nrows=2, ncols=10, sharex=True, sharey=True, figsize=(25,4))\n",
    "\n",
    "# input images on top row, reconstructions on bottom\n",
    "for noisy_imgs, row in zip([noisy_imgs, output], axes):\n",
    "    for img, ax in zip(noisy_imgs, row):\n",
    "        ax.imshow(np.squeeze(img), cmap='gray')\n",
    "        ax.get_xaxis().set_visible(False)\n",
    "        ax.get_yaxis().set_visible(False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
